﻿/**
* CRL
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections;
using CRL.ExistsTableCache;
using System.Net.Http.Headers;
using System.Security.AccessControl;

namespace CRL.LambdaQuery
{

    public abstract partial class LambdaQuery<T> : LambdaQueryBase
    {
        public ILambdaQuery<T> Include()
        {
            var members = typeof(T).GetProperties().Where(b => b.PropertyType.IsClass && b.PropertyType != typeof(string));
            var dbFields = TypeCache.GetTable(typeof(T)).Fields.Select(b => b.MemberName);
            members = members.Where(b => !dbFields.Contains(b.Name));
            foreach (var m in members)
            {
                var method = GetType().GetMethod(nameof(IncludeBase), BindingFlags.Instance | BindingFlags.NonPublic);
                var parameter = Expression.Parameter(typeof(T), "b");
                var exp = Expression.PropertyOrField(parameter,m.Name);
                method.MakeGenericMethod(new Type[] { m.PropertyType }).Invoke(this, new object[] { exp });
            }
            return this;
        }
        public ILambdaQuery<T> Include<TChild>(Expression<Func<T, TChild>> expression)
        {
            return IncludeBase<TChild>(expression.Body);
        }
        internal ILambdaQuery<T> IncludeBase<TChild>(Expression expressionBody)
        {
            if (typeof(IEnumerable).IsAssignableFrom(typeof(TChild)))
            {
                var mcExp = (MemberExpression)expressionBody;
                var firstType = mcExp.Type.GetGenericArguments().First();
                var method = GetType().GetMethod(nameof(__Include), BindingFlags.Instance | BindingFlags.NonPublic);
                method.MakeGenericMethod(new Type[] { firstType }).Invoke(this, new object[] { expressionBody, null });
                return this;
            }
            var rf = __Include<TChild>(expressionBody);
            __Join<TChild>(rf.parameters, rf.expression, JoinType.Inner);
            var exp = Expression.Parameter(typeof(TChild), "b");
            var fields = GetSelectField(true, exp, true, typeof(TChild));
            //排除集合类型
            fields.mapping.RemoveAll(b => typeof(IEnumerable).IsAssignableFrom(b.PropertyType) && b.PropertyType != typeof(string));
            SetSelectFiled(fields);
            return this;
        }
        public ILambdaQuery<T> Include<TChild>(Expression<Func<T, IEnumerable<TChild>>> expression, Expression<Func<TChild, bool>> filter = null)
        {
            __Include(expression.Body, filter);
            return this;
        }
        internal RelationInfo __Include<TChild>(Expression expressionBody, Expression<Func<TChild, bool>> childFilter = null)
        {
            var mcExp = (MemberExpression)expressionBody;
            var firstType = mcExp.Type;
            var types2 = firstType.GetGenericArguments();
            if (types2.Any())
            {
                firstType = types2.First();
            }
            var rf = AbsPropertyBuilder.FindRelationInfo(__MainType, firstType);
            if (rf == null)
            {
                throw new Exception($"未找到关系配置:{__MainType} {firstType}");
            }
            var query2 = LambdaQueryFactory.CreateLambdaQuery<TChild>(__DbContext);
            if (childFilter != null)
            {
                query2.Where(childFilter);
            }
            __IncludeTypes = __IncludeTypes ?? new Dictionary<Type, includeInfo>();
            __IncludeTypes.Add(firstType, new includeInfo { MemberName = mcExp.Member.Name, Query = query2, MainType = __MainType });
            return rf;
        }

    }
    internal class includeInfo
    {
        public Type MainType;
        public string MemberName;
        public LambdaQueryBase Query;
    }
}
